﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Common.Utilities;

namespace PdfLib
{
    /// <summary>
    /// limit to max of 1 line for page header and page footer
    /// header must be within top 1/4 region of page
    /// footer must be within bottom 1/4 region of page
    /// header of footer must be present more than twice and in 3/4 of pages
    /// excluding pages that may be image or face page 
    /// (no content on top/bottom edges of page)
    /// </summary>
    public class PdfPageHeaderFooterReader
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pdfFilePath"></param>
        /// <param name="pagesContainingHeader"></param>
        /// <returns></returns>
        public static PdfPageHeader ReadPageHeader(string pdfFilePath, List<int> pagesContainingHeader)
        {
            pagesContainingHeader=new List<int>();
            Dictionary<int, PdfTextLine> pageTopLines = new Dictionary<int, PdfTextLine>();
            int pageCount = PdfPropertyReader.GetPageCount(pdfFilePath);
            for(int pageNum=1; pageNum<=pageCount;pageNum++)
            {
                List<PdfTextToken> txtTokens = PdfTextReader.ReadPageContentAsTokens(pdfFilePath, pageNum);
                if(txtTokens==null || txtTokens.Count==0)
                    continue;
                List<PdfTextLine> lines = PdfTextReader.CreateLines(txtTokens);
                lines = PdfTextReader.MergeLines(lines, 8.0);
                lines.Sort();
                pageTopLines.Add(pageNum, lines[0]);
            }

            
            Dictionary<string,List<int>> headerOccurances=new Dictionary<string, List<int>>();
            foreach(int pageNum in pageTopLines.Keys)
            {
                SizeF pageSize = PdfPropertyReader.GetPageSize(pdfFilePath, pageNum);
                if(pageTopLines[pageNum].Rect.Top >= pageSize.Height /4)
                    continue;

                bool exist = false;
                string headerContent = pageTopLines[pageNum].LineContent;
                if(headerOccurances.Count>0)
                {
                    string[] headerContents=new string[headerOccurances.Count];
                    headerOccurances.Keys.CopyTo(headerContents, 0);
                    for(int i=0;i<headerContents.Length;i++)
                    {
                        string existingHeaderContent = headerContents[i];
                        string matchedStringContent = string.Empty;
                        int matchedStringLen =
                            StringUtil.LongestCommonSubsequence(
                                headerContent, existingHeaderContent, ref matchedStringContent);
                        double matchScore1 =
                            (double) Math.Min(matchedStringLen, matchedStringContent.Length)/
                            headerContent.Length;
                        double matchScore2 =
                            (double) StringUtil.LongestCommonSubString(headerContent, existingHeaderContent)/
                            headerContent.Length;
                        double matchScore = Math.Min(matchScore1, matchScore2);
                        if(matchScore>0.90)
                        {
                            exist = true;
                            headerOccurances[existingHeaderContent].Add(pageNum); 
                            break;
                        }
                    }
                }
                if(!exist)
                {
                    List<int> pageNumsContainingHeader=new List<int>();
                    pageNumsContainingHeader.Add(pageNum);
                    headerOccurances.Add(headerContent, pageNumsContainingHeader);
                }
            }

            int pagesHavingTopEdges = 0;
            foreach (string headerContent in headerOccurances.Keys)
            {
                pagesHavingTopEdges += headerOccurances[headerContent].Count;
            }
            int minimumPagesContainingHeader = Math.Max(2, pagesHavingTopEdges*3/4);
            foreach(string headerContent in headerOccurances.Keys)
            {
                if(headerOccurances[headerContent].Count>=minimumPagesContainingHeader)
                {
                    pagesContainingHeader = headerOccurances[headerContent];
                    PdfTextLine headerLine = pageTopLines[headerOccurances[headerContent][0]];
                    PdfPageHeader header=new PdfPageHeader(headerContent, headerLine.Rect);
                    return header;
                }
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pdfFilePath"></param>
        /// <param name="pagesContainingFooter"></param>
        /// <returns></returns>
        public static PdfPageFooter ReadPageFooter(
            string pdfFilePath, List<int> pagesContainingFooter)
        {
            pagesContainingFooter = new List<int>();
            Dictionary<int, PdfTextLine> pageBottomLines = new Dictionary<int, PdfTextLine>();
            int pageCount = PdfPropertyReader.GetPageCount(pdfFilePath);
            for (int pageNum = 1; pageNum <= pageCount; pageNum++)
            {
                List<PdfTextToken> txtTokens = PdfTextReader.ReadPageContentAsTokens(pdfFilePath, pageNum);
                if (txtTokens == null || txtTokens.Count == 0)
                    continue;
                List<PdfTextLine> lines = PdfTextReader.CreateLines(txtTokens);
                lines = PdfTextReader.MergeLines(lines, 8.0);
                lines.Sort();
                PdfTextLine bottomLine = lines[lines.Count - 1];
                pageBottomLines.Add(pageNum, bottomLine);
            }


            Dictionary<string, List<int>> footerOccurances = new Dictionary<string, List<int>>();
            foreach (int pageNum in pageBottomLines.Keys)
            {
                SizeF pageSize = PdfPropertyReader.GetPageSize(pdfFilePath, pageNum);
                if (pageBottomLines[pageNum].Rect.Bottom <= (pageSize.Height * 3 / 4))
                    continue;

                bool exist = false;
                string footerContent = pageBottomLines[pageNum].LineContent;
                if (footerOccurances.Count > 0)
                {
                    string[] footerContents = new string[footerOccurances.Count];
                    footerOccurances.Keys.CopyTo(footerContents, 0);
                    for (int i = 0; i < footerContents.Length; i++)
                    {
                        string existingFooterContent = footerContents[i];
                        string matchedStringContent = string.Empty;
                        int matchedStringLen =
                            StringUtil.LongestCommonSubsequence(
                                footerContent, existingFooterContent, ref matchedStringContent);
                        double matchScore1 =
                            (double)Math.Min(matchedStringLen, matchedStringContent.Length) /
                            footerContent.Length;
                        double matchScore2 =
                            (double)StringUtil.LongestCommonSubString(footerContent, existingFooterContent) /
                            footerContent.Length;
                        double matchScore = Math.Min(matchScore1, matchScore2);
                        if (matchScore > 0.90)
                        {
                            exist = true;
                            footerOccurances[existingFooterContent].Add(pageNum);
                            break;
                        }
                    }
                }
                if (!exist)
                {
                    List<int> pageNumsContainingFooter = new List<int>();
                    pageNumsContainingFooter.Add(pageNum);
                    footerOccurances.Add(footerContent, pageNumsContainingFooter);
                }
            }

            int pagesHavingBottomEdges = 0;
            foreach (string footerContent in footerOccurances.Keys)
            {
                pagesHavingBottomEdges += footerOccurances[footerContent].Count;
            }
            int minimumPagesContainingFooter = Math.Max(2, pagesHavingBottomEdges * 3 / 4);
            foreach (string footerContent in footerOccurances.Keys)
            {
                if (footerOccurances[footerContent].Count >= minimumPagesContainingFooter)
                {
                    pagesContainingFooter = footerOccurances[footerContent];
                    PdfTextLine footerLine = pageBottomLines[footerOccurances[footerContent][0]];
                    PdfPageFooter footer = new PdfPageFooter(footerContent, footerLine.Rect);
                    return footer;
                }
            }
            return null;
        }
    }
}
